home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / ccmd / ccmdio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-05  |  14.8 KB  |  491 lines

  1. /*
  2.  Author: Andrew Lowry
  3.  
  4.  Columbia University Center for Computing Activities, July 1986.
  5.  Copyright (C) 1986, 1987, Trustees of Columbia University in the City
  6.  of New York.  Permission is granted to any individual or institution
  7.  to use, copy, or redistribute this software so long as it is not sold
  8.  for profit, provided this copyright notice is retained.
  9. */
  10. /* ccmdio.c
  11. **
  12. ** Routines to perform console i/o with a built-in column counting 
  13. ** mechanism.  The column count is maintained in CSB variable
  14. ** _cmcol, and the routine names all start with "cmx".  Most routines
  15. ** make use of a parallel machine-dependent routine whose name starts
  16. ** with "cm".  In general, output characters must be printable 
  17. ** and must occupy a single printing position each.  If an attempt is
  18. ** made to print past the maximum column position specified in _cmcmx
  19. ** in the CSB, the line is broken automatically.
  20. **/
  21.  
  22. #include "ccmdlib.h"            /* get ccmd package symbols */
  23. #include "cmfncs.h"            /* and internal symbols */
  24.  
  25. static int ignlines;            /* for use with redraw routine */
  26.  
  27. char lastchar = '\0';            /* last character in ESCAPE sequence */
  28.  
  29. /* cmxputc - Output single character c */
  30.  
  31. cmxputc(c)
  32. char c;
  33. {
  34. #ifdef undef
  35.   if ((cmcsb._cmflg & CM_TTY) == 0)
  36.     return;                /* do nothing on non-terminal */
  37. #endif
  38.   if (c == NEWLINE) {
  39.     cmxnl(cmcsb._cmoj);            /* handle newlines properly */
  40.     return;
  41.   }
  42.   if (cmcsb._cmcol > cmcsb._cmcmx)
  43.     cmxwrap(cmcsb._cmoj);        /* wrap to new line if needed */
  44.   if (ignlines == 0)            /* if not ignoring this line */
  45.     cmputc(c,cmcsb._cmoj);        /* output the character */
  46.   if ((c == '\033') || (lastchar == '\033' && ((c == '$') || (c == '('))))
  47.     lastchar = c;            /* note last character */
  48.   else {
  49.     if (!(((lastchar == '$') && (c == 'B')) ||
  50.       ((lastchar == '(') && (c == 'J'))))
  51.       cmcsb._cmcol++;            /* count if not JIS */
  52.     lastchar = '\0';            /* either way, no more JIS */
  53.   }
  54. }
  55.  
  56. /* cmxputs - Output string of characters pointed to by s */
  57.  
  58. cmxputs(s)
  59. char *s;
  60. {
  61.   int slen,brkpos;            /* length of s, position for break */
  62.   char temp;                /* holds char in break position */
  63.   
  64. #ifdef undef
  65.   if ((cmcsb._cmflg & CM_TTY) == 0)
  66.     return;                /* do nothing on non-terminal */
  67. #endif
  68.   slen = strlen(s);            /* find length of string */
  69.   while ((brkpos = (cmcsb._cmcmx+1) - cmcsb._cmcol) < slen) { /* too long */
  70.     temp = s[brkpos];            /* save char from break position */
  71.     s[brkpos] = NULCHAR;        /* replace with string terminator */
  72.     cmputs(s,cmcsb._cmoj);        /* output as much as will fit */
  73.     cmxwrap(cmcsb._cmoj);        /* then move to next line */
  74.     s[brkpos] = temp;            /* restore original character */
  75.     s += brkpos;            /* move forward in string */
  76.     slen -= brkpos;            /* count those characters output */
  77.   }
  78.   cmputs(s,cmcsb._cmoj);        /* finally, the last segment */
  79.   cmcsb._cmcol += slen;            /* and update column position */
  80. }
  81.  
  82. cmxerr(s) char *s; {
  83.   int slen,brkpos;            /* length of s, position for break */
  84.   char temp;                /* holds char in break position */
  85.   
  86.   slen = strlen(s);            /* find length of string */
  87.   while ((brkpos = (cmcsb._cmcmx+1) - cmcsb._cmcol) < slen) { /* too long */
  88.     temp = s[brkpos];            /* save char from break position */
  89.     s[brkpos] = NULCHAR;        /* replace with string terminator */
  90.     cmputs(s,cmcsb._cmej);        /* output as much as will fit */
  91.     cmxwrap(cmcsb._cmej);        /* then move to next line */
  92.     s[brkpos] = temp;            /* restore original character */
  93.     s += brkpos;            /* move forward in string */
  94.     slen -= brkpos;            /* count those characters output */
  95.   }
  96.   cmputs(s,cmcsb._cmej);        /* finally, the last segment */
  97.   cmcsb._cmcol += slen;            /* and update column position */
  98. }
  99.  
  100. /* cmxbol - Move to new line if not already at left screen edge */
  101.  
  102. cmxbol()
  103. {
  104. #ifdef undef
  105.   if ((cmcsb._cmflg & CM_TTY) == 0)
  106.     return;                /* do nothing on non-terminal */
  107. #endif
  108.   if (cmcpos() != 0)
  109.     cmnl(cmcsb._cmoj);            /* move if necessary */
  110.   cmcsb._cmcol = 0;            /* fix column counter */
  111. }
  112.  
  113. /* cmxnl - Output a newline sequence, and reset column counter */
  114.  
  115. cmxnl()
  116. {
  117. #ifdef undef
  118.   if ((cmcsb._cmflg & CM_TTY) == 0)
  119.     return;                /* do nothing on non-terminal */
  120. #endif
  121.   if (ignlines == 0)            /* if not ignoring this line */
  122.     cmnl(cmcsb._cmoj);            /* output the newline */
  123.   else
  124.     ignlines--;                /* else drop the count */
  125.   cmcsb._cmcol = 0;            /* and reset counter */
  126. }
  127.  
  128. /* cmxwrap - Wrap from the end of one line to the beginning of the next */
  129.  
  130. cmxwrap()
  131. {
  132. #ifdef undef
  133.   if ((cmcsb._cmflg & CM_TTY) == 0)
  134.     return;                /* do nothing on non-terminal */
  135. #endif
  136.   if (ignlines == 0)            /* if not ignoring this line */
  137.     cmwrap(cmcsb._cmoj);        /* do the wrap */
  138.   else
  139.     ignlines--;                /* else drop the count */
  140.   cmcsb._cmcol = 0;            /* and reset column counter */
  141. }
  142.  
  143.  
  144. /* cmxcls - Clear the screen and reset the column counter */
  145.  
  146. cmxcls()
  147. {
  148.   if ((cmcsb._cmflg & CM_CRT) == 0)
  149.     return;                /* do nothing on non-crt */
  150.   if (!cmcls())                /* clear the screen */
  151.     cmnl(cmcsb._cmoj);            /* or at least go to new line */
  152.   cmcsb._cmcol = 0;            /* reset the counter */
  153. }
  154.  
  155.  
  156. /* cmxcll - Clear the current line on the terminal screen */
  157.  
  158. cmxcll()
  159. {
  160.   int col = cmcsb._cmcol;        /* save position before clear */
  161.   if ((cmcsb._cmflg & CM_CRT) == 0)
  162.     return;                /* do nothing on non-crt */
  163.   cmcr(cmcsb._cmoj);            /* back to left margin */
  164.   if (!cmceol()) {            /* clear to end of line */
  165.     while (col-- > 0)            /* no luck... do it with spaces */
  166.       cmputc(SPACE,cmcsb._cmoj);
  167.     cmcr(cmcsb._cmoj);            /* back to the beginning */
  168.   }
  169.   cmcsb._cmcol = 0;
  170. }
  171.  
  172. /* cmxera
  173. **
  174. ** Purpose:
  175. **   Erases a portion of the current command line from the screen.
  176. **   The CSB itself is left unchanged.  Erasure takes into effect
  177. **   the translations performed by the echo routine in ccmdut, and
  178. **   characters that were not echoed are not erased.  Optionally,
  179. **   the prompt is redisplayed when the entire command line is
  180. **   erased.  The new screen column position after erasure is
  181. **   returned.
  182. **
  183. ** Input arguments:
  184. **   n - Number of chars to erase from the end of input.
  185. **   doprompt - If TRUE, and if entire buffer erased, prompt is refreshed.
  186. **
  187. ** Returns: New screen column position.
  188. **/
  189.  
  190. int
  191. cmxera(n,doprompt)
  192. int n,doprompt;
  193. {
  194.   int lpos1,cpos1;        /* line and column position before erase */
  195.   int lpos2,cpos2;        /* and after erasure */
  196.   int lpos1x;            /* extra copy of lpos1 */
  197.   int lsize;            /* width of text on a given line */
  198.   int i;
  199.  
  200.   countbuf(0,&lpos1,&cpos1);        /* get current position */
  201.   countbuf(n,&lpos2,&cpos2);        /* and after erasure */
  202.   lpos1x = lpos1;
  203.   if ((cmcsb._cmflg & CM_CRT) == 0)
  204.     return(cpos2);            /* do nothing on non-crt */
  205.  
  206.   if ((lpos1 != lpos2) || (cpos2 == 0)) { /* killing at least one full line */
  207.     cmcr(cmcsb._cmoj);            /* get to left screen edge */
  208.     while (lpos1-- > lpos2) {        /* kill abandoned lines */
  209.       if (!cmceol()) {            /* clear out one line  */
  210.     lsize = countline(lpos1+1); /* no luck...see how many chars to clear */
  211.     while (lsize-- > 0)
  212.           cmputc(SPACE,cmcsb._cmoj);    /* and write over them with spaces */
  213.     cmcr(cmcsb._cmoj);        /* then back to beginning of line */
  214.       }
  215.       if (!cmupl()) {            /* then move up to next line */
  216.         cmputc(BS,cmcsb._cmoj);        /* no luck.. try backspace-return */
  217.     cmcr(cmcsb._cmoj);
  218.       }
  219.     }
  220.   }
  221.   if ((lpos1x == lpos2) && (cpos2 != 0)) /* same line, not beginning? */
  222.     for (i = cpos2; i < cpos1; i++)
  223.       cmputc(BS,cmcsb._cmoj);        /* backsapce to new column */
  224.   else  
  225.     redraw(lpos2,cpos2);        /* redraw the final line */
  226.   if (!cmceol()) {            /* kill the rest of it */
  227.     lsize = countline(lpos2)-cpos2;    /* no luck... count excess chars */
  228.     for (i = 0; i < lsize; i++)
  229.       cmputc(SPACE,cmcsb._cmoj);    /* overwrite with spaces */
  230.     for (i = 0; i < lsize; i++)
  231.       cmputc(BS,cmcsb._cmoj);        /* then backspace back into position */
  232.   }      
  233.   if (n == (cmcsb._cminc + (cmcsb._cmptr - cmcsb._cmbfp)))
  234.     if (doprompt) {            /* entire buffer erased and prompt wanted? */
  235.       cmcr(cmcsb._cmoj);        /* yup, back to beginning of line */
  236.       if (!cmceol()) {            /* erase prior prompt */
  237.     lsize = cpos2;            /* no luck... see how many chars to erase */
  238.     while (lsize-- > 0)
  239.           cmputc(SPACE,cmcsb._cmoj);    /* erase with spaces */
  240.     cmcr(cmcsb._cmoj);        /* and back to beginning */
  241.       }
  242.       cmputs(cmcsb._cmrty,cmcsb._cmoj); /* and redisplay the prompt */
  243.     }
  244.   return(cpos2);        /* return new column position */
  245. }
  246.  
  247. /* countbuf
  248. **
  249. ** Purpose:
  250. **   Compute line and column position (relative to beginning of prompt
  251. **   string) that would result from displaying the current command line,
  252. **   truncated by a given number of characters from the end.  Non-echoed
  253. **   characters and special translations provided by the echo routine in
  254. **   module ccmdut are taken into account.
  255. **
  256. ** Input parameters:
  257. **   n - The number of characters to exclude from the end of the input.
  258. **
  259. ** Output parameters:
  260. **   lpos - Number of lines from the one containing the beginning of the
  261. **     prompt string.
  262. **   cpos - Column position (0 = left edge of screen).
  263. **/
  264.  
  265. static
  266. countbuf(n,lpos,cpos)
  267. int n,*lpos,*cpos;
  268. {
  269.   int count;                /* counts characters */
  270.   int *cp,cc;                /* for scanning buffer characters */
  271.   char c;
  272.   char clastchar = '\0';
  273.  
  274.   count = strlen(cmcsb._cmrty);        /* get length of prompt string */
  275.   *lpos = count / (cmcsb._cmcmx);    /* compute prompt end coordinates */
  276.   *cpos = count % (cmcsb._cmcmx);
  277.                     /* get # of buffer chars to count */
  278.   count = cmcsb._cminc + (cmcsb._cmptr - cmcsb._cmbfp) - n;
  279.   cp = cmcsb._cmbfp;            /* point to buffer start */
  280.   while (count-- > 0) {            /* loop through chars */
  281.     c = (cc = *cp++) & CC_CHR;        /* get next char */
  282.     if (cc & CC_NEC)
  283.       continue;                /* non-echoed char... no count */
  284.     else if (c == NEWLINE) {
  285.       (*lpos)++;            /* newline... move to next line */
  286.       *cpos = 0;            /* and reset column counter */
  287.     }
  288.     else if (c == TAB) {        /* TAB character */
  289.       *cpos = 8 + 8*(*cpos / 8);    /* move col to next multiple of 8 */
  290.       if (*cpos >= cmcsb._cmcmx) {    /* wrap if necessary */
  291.     (*lpos)++;            /* to next line */
  292.     *cpos = 0;            /* column zero */
  293.       }
  294.     }
  295.                     /* JIS sequence test */
  296.     else if ((c == '\033') || (clastchar == '\033' &&
  297.                    ((c == '$') || (c == '('))))
  298.       clastchar = c;            /* note last character */
  299.     else {
  300.       if (!(((clastchar == '$') && (c == 'B')) ||
  301.         ((clastchar == '(') && (c == 'J')))) {
  302.     if ((c == DELETE) || (c < SPACE)) /* other control char */
  303.       *cpos += 2;            /* count up-arrow and print char */
  304.     else                /* normal printing char */
  305.       (*cpos)++;            /* count it */
  306.     if (*cpos >= cmcsb._cmcmx) {    /* wrap if necessary */
  307.       (*lpos)++;
  308.       *cpos %= cmcsb._cmcmx;
  309.     }
  310.     clastchar = '\0';
  311.       }
  312.     }
  313.   }
  314. }
  315.  
  316.  
  317.  
  318. /* countline
  319. **
  320. ** Purpose - Determine how wide a given line is on the current
  321. ** display.
  322. **
  323. ** Input arguments:
  324. **   line - Number of line to count, 0 = prompt line
  325. **
  326. ** Output arguments: None
  327. ** Returns: Number of columns occupied by text on the given line.
  328. **/
  329.  
  330. static int
  331. countline(line)
  332. int line;
  333. {
  334.   int count;                /* counts characters */
  335.   int lpos,cpos;                /* keep track of position */
  336.   int *cp,cc;                /* for scanning buffer characters */
  337.   char c;
  338.  
  339.   count = strlen(cmcsb._cmrty);        /* get length of prompt string */
  340.   lpos = count / cmcsb._cmcmx;        /* compute prompt end coordinates */
  341.   cpos = count % (cmcsb._cmcmx+1);
  342.   if (line < lpos)            /* part of prompt */
  343.     return(cmcsb._cmcmx+1);        /* indicate whole line */
  344.  
  345.                     /* get # of buffer chars to count */
  346.   count = cmcsb._cminc + (cmcsb._cmptr - cmcsb._cmbfp);
  347.   cp = cmcsb._cmbfp;            /* point to buffer start */
  348.   while (count-- > 0) {            /* loop through chars */
  349.     c = (cc = *cp++) & CC_CHR;        /* get next char */
  350.     if (cc & CC_NEC)
  351.       continue;                /* non-echoed char... no count */
  352.     else if (c == NEWLINE) {
  353.       if (lpos == line)            /* newline - finished given line? */
  354.         return(cpos);            /* yup, return its width */
  355.       lpos++;                /* no, move to next line */
  356.       cpos = 0;                /* and reset column counter */
  357.     }
  358.     else if (c == TAB) {        /* TAB character */
  359.       cpos = 8 + 8*((cpos) / 8);    /* move col to next multiple of 8 */
  360.       if (cpos > cmcsb._cmcmx) {    /* wrap if necessary */
  361.     if (lpos == line)        /* finished given line? */
  362.       return(cmcsb._cmcmx + 1);    /* yup, it used all its columns */
  363.     lpos++;                /* no, move to next line */
  364.     cpos = 0;            /* column zero */
  365.       }
  366.     }
  367.     else {
  368.       if ((c == DELETE) || (c < SPACE)) /* other control char */
  369.         cpos += 2;            /* count up-arrow and print char */
  370.       else                /* normal printing char */
  371.         cpos++;                /* count it */
  372.       if (cpos > cmcsb._cmcmx) {    /* wrap if necessary */
  373.     if (lpos == line)        /* finished given line? */
  374.       return(cmcsb._cmcmx+1);    /* yup, it used entire width */
  375.     lpos++;                /* no, move to next line */
  376.     cpos %= cmcsb._cmcmx+1;
  377.       }
  378.     }
  379.   }
  380.   return(cpos);                /* given line was last line */
  381. }
  382.  
  383.  
  384.  
  385. /* redraw
  386. **
  387. ** Purpose:
  388. **   Redisplay a given line from the command display, up to but
  389. **   not including a given column position.  Will never be called
  390. **   with a column number such that redisplay must be turned off
  391. **   in the middle of a multi-character translation by cmechx.
  392. **
  393. ** Input arguments:
  394. **   line - Line number to be redisplayed
  395. **   col - Column position to end redisplay
  396. **
  397. ** Output arguments: None.
  398. ** Returns: Nothing.
  399. **/
  400.  
  401. static
  402. redraw(line,col)
  403. int line,col;
  404. {
  405.   char *pmt;                /* prompt string */
  406.   int *cp;                /* pointer to command buffer */
  407.  
  408.   if (col == 0)
  409.     return;                /* no replay required on line */
  410.   ignlines = line;            /* set number of lines to ignore */
  411.   cmcsb._cmcol = 0;            /* reset column counter */
  412.   pmt = cmcsb._cmrty;            /* point to prompt string */
  413.   while (*pmt != NULCHAR)
  414.     cmxputc(*pmt++);            /* output the prompt */
  415.   
  416.   cp = cmcsb._cmbfp;            /* point to beginning of buffer */
  417.   while ((ignlines > 0) || (cmcsb._cmcol < col)) 
  418.     if ((*cp & CC_NEC) == 0)        /* loop through buffer */
  419.       cmechx((char) (*cp++) & CC_CHR);    /* echo chars that were originally */
  420.     else
  421.       cp++;                /* skipping those that were not */
  422.                     /* possible JIS sequence? */
  423.   if ((((char) *cp) & CC_CHR) == '\033') {
  424.     cmechx ((char) (*cp++) & CC_CHR);    /* ugh, gross kludge */
  425.     cmechx ((char) (*cp++) & CC_CHR);
  426.     cmechx ((char) (*cp++) & CC_CHR);
  427.   }
  428.   return;                /* all done */
  429. }
  430.  
  431. /*
  432.  * cmxflsh()
  433.  * flush output on csb output stream
  434.  */
  435. cmxflsh() {
  436.   cmflsh(cmcsb._cmoj);
  437. }
  438.  
  439. /*
  440.  * do a printf to our output file
  441.  */
  442.  
  443.  
  444. cmxprintf(va_alist) va_dcl {
  445.   char *fmt;
  446.   va_list arg_ptr;
  447.   int ret;
  448.  
  449.   if (cmcsb._cmoj == NULL)
  450.       return(0);
  451.   va_start(arg_ptr);
  452.   fmt = va_arg(arg_ptr, char *);
  453.   ret = vfprintf(cmcsb._cmoj,fmt,arg_ptr);
  454.   va_end(arg_ptr);
  455.   return ret;
  456. }
  457.  
  458. /*
  459.  * do a printf to our error file
  460.  */
  461.  
  462. cmxeprintf(va_alist) va_dcl {
  463.   char *fmt;
  464.   va_list arg_ptr;
  465.   int ret;
  466.  
  467.   if (cmcsb._cmej == NULL)
  468.       return(0);
  469.   va_start(arg_ptr);
  470.   fmt = va_arg(arg_ptr, char *);
  471.   ret = vfprintf(cmcsb._cmej,fmt,arg_ptr);
  472.   va_end(arg_ptr);
  473.   return ret;
  474. }
  475.  
  476. #ifdef BSD
  477. extern int _doprnt();
  478.  
  479. int
  480. vfprintf(iop, format, ap)
  481. FILE *iop;
  482. char *format;
  483. va_list ap;
  484. {
  485.     int count;
  486.  
  487.     count = _doprnt(format, ap, iop);
  488.     return(ferror(iop)? EOF: count);
  489. }
  490. #endif /* BSD */
  491.